//
//  WAWeatherProvider.m
//  WeatherApp
//
//  Created by Yuliya Grasevych on 23.07.14.
//  Copyright (c) 2014 Yuliya Grasevych. All rights reserved.
//

#import "WAWeatherProvider.h"
#import "WACurrentWeather.h"
#import "WAWeatherForecast.h"
#import "WAFlickrManager.h"
#import "NSObject+CastToClass.h"
#import "WAYahooInfoProvider.h"
#import "NSDate+SeasonByHemisphere.h"

NSString *const kCurrentLocationKey = @"CurrentLocationKey";
NSString *const kLocationWeatherDidUpdate = @"LocationDidUpdate";
NSString *const kLocationWeatherBackgroundDidUpdate = @"LocationWeatherBackgroundDidUpdate";

@interface WAWeatherProvider () <CLLocationManagerDelegate>

@property (nonatomic) NSMutableDictionary *innerLocationsWeathers;
@property (nonatomic) NSMutableArray *innerLocations;
@property (nonatomic) CLLocationManager *locationManager;
-(void)getCurrentLocation;

@end


@implementation WAWeatherProvider

+(id)sharedInstance
{
    static WAWeatherProvider *_sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        _sharedInstance = [[WAWeatherProvider alloc] init];
        [[NSNotificationCenter defaultCenter] addObserver:_sharedInstance selector:@selector(locationDidUpdate:) name:kWALocationDidUpdate object:nil];
        [_sharedInstance startMonitoringLocation];
    });
    return _sharedInstance;
}
-(NSMutableDictionary *)innerLocationsWeathers
{
    if (!_innerLocationsWeathers) {
        
        _innerLocationsWeathers = [NSMutableDictionary dictionaryWithCapacity:1];
    }
    return _innerLocationsWeathers;
}
-(NSDictionary *)locationsWeathers
{
    return self.innerLocationsWeathers;
}

-(NSMutableArray *)innerLocations
{
    if (!_innerLocations) {
        
        _innerLocations = [NSMutableArray arrayWithCapacity:1];
        [_innerLocations addObject:kCurrentLocationKey];
    }
    return _innerLocations;
}
-(NSArray *)locations
{
    return self.innerLocations;
}

-(void)addLocation:(id)val
{
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&val count:1];
    
    [self willChangeValueForKey:@"locations"
                withSetMutation:NSKeyValueUnionSetMutation
                   usingObjects:changedObjects];
    [[self innerLocations] addObject:val];
    [self didChangeValueForKey:@"locations"
               withSetMutation:NSKeyValueUnionSetMutation
                  usingObjects:changedObjects];
    
    //    [self.innerLocations addObject:location];
    [self updateLocationForKey:val];
}
-(void)removeLocation:(id)val
{
    NSSet *changedObjects = [[NSSet alloc] initWithObjects:&val count:1];
    
    [self willChangeValueForKey:@"locations"
                withSetMutation:NSKeyValueMinusSetMutation
                   usingObjects:changedObjects];
    [[self innerLocations] removeObject:val];
    [self.innerLocationsWeathers removeObjectForKey:val];
    [self didChangeValueForKey:@"locations"
               withSetMutation:NSKeyValueMinusSetMutation
                  usingObjects:changedObjects];
    
    //    [self.innerLocations removeObject:location];
    //    [self.innerLocationsWeathers removeObjectForKey:location];
}
-(void)updateAllLocations
{
    [self getCurrentLocation];
    [self.locations enumerateObjectsUsingBlock:^(NSObject <NSCopying> *key, NSUInteger idx, BOOL *stop) {
        // update all locations except current
        if ([key isKindOfClass:[WALocation class]]) {
            
            [self updateLocationForKey:key];
        }
    }];
}

- (void)getWeatherForLocation:(WALocation *)location forKey:(NSObject <NSCopying> *)locationKey
{
    NSDictionary *requestParams = @{@"q": [NSString stringWithFormat:@"select * from weather.forecast where woeid=%@ and u=\"c\"", location.woeid],
                                    @"format": @"json"};
    [[WAYahooInfoProvider sharedInstance] yahooRequestWithStatement:requestParams
                                                  completionHandler:^(NSError *error, NSDictionary *jsonData) {
                                                      
                                                      if (!error) {
                                                          
                                                          NSDictionary *query = [jsonData objectForKey:@"query"];
                                                          NSDictionary *results = [query objectForKey:@"results"];
                                                          NSDictionary *channel = [results objectForKey:@"channel"];
                                                          NSDictionary *atmosphere = [channel objectForKey:@"atmosphere"];
                                                          NSDictionary *astronomy = [channel objectForKey:@"astronomy"];
                                                          NSDictionary *item = [channel objectForKey:@"item"];
                                                          
                                                          WACurrentWeather *curWeather = [[WACurrentWeather alloc] init];
                                                          curWeather.humidity = [[atmosphere objectForKey:@"humidity"] integerValue];
                                                          curWeather.pressure = [[atmosphere objectForKey:@"pressure"] floatValue];
                                                          
                                                          NSDateFormatter *sunDateFormatter = [[NSDateFormatter alloc] init];
                                                          [sunDateFormatter setDateFormat:@"h:m a"];
                                                          [sunDateFormatter setFormatterBehavior:NSDateFormatterBehavior10_0];
                                                          NSDate *sunrise = [sunDateFormatter dateFromString:[astronomy objectForKey:@"sunrise"]];
                                                          curWeather.sunrise = sunrise;
                                                          NSDate *sunset = [sunDateFormatter dateFromString:[astronomy objectForKey:@"sunset"]];
                                                          curWeather.sunset = sunset;
                                                          
                                                          NSDictionary *condition = [item objectForKey:@"condition"];
                                                          curWeather.currentTemperature = [[condition objectForKey:@"temp"] integerValue];
                                                          curWeather.weatherDescription = [condition objectForKey:@"text"];
                                                          curWeather.code = [[condition objectForKey:@"code"] integerValue];
                                                          
                                                          NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
                                                          [dateFormatter setDateFormat:@"EEE, d MMM yyyy h:mm a z"];
                                                          [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_0];
                                                          NSDate *curDate = [dateFormatter dateFromString:[condition objectForKey:@"date"]];
                                                          curWeather.date = curDate;
                                                          
                                                          NSArray *forecast = [item objectForKey:@"forecast"];
                                                          NSMutableArray *curForecasts = [NSMutableArray arrayWithCapacity:4];
                                                          [forecast enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop) {
                                                              
                                                              WAWeatherForecast *weatherForecast = [[WAWeatherForecast alloc] init];
                                                              weatherForecast.code = [[obj objectForKey:@"code"] integerValue];
                                                              weatherForecast.highTemp = [[obj objectForKey:@"high"] integerValue];
                                                              weatherForecast.lowTemp = [[obj objectForKey:@"low"] integerValue];
                                                              weatherForecast.weatherDescription = [obj objectForKey:@"text"];
                                                              
                                                              NSDateFormatter *forecastDateFormatter = [[NSDateFormatter alloc] init];
                                                              [forecastDateFormatter setDateFormat:@"d MMM yyyy"];
                                                              [forecastDateFormatter setFormatterBehavior:NSDateFormatterBehavior10_0];
                                                              NSDate *forecastDate = [forecastDateFormatter dateFromString:[obj objectForKey:@"date"]];
                                                              weatherForecast.date = forecastDate;
                                                              [curForecasts insertObject:weatherForecast atIndex:idx];
                                                          }];
                                                          curWeather.weatherForecasts = curForecasts;
                                                          
                                                          NSString *dayCondition = ([[NSDate date] compare:curWeather.sunset]==NSOrderedAscending) ?
                                                          ( ([[NSDate date] compare:curWeather.sunrise]==NSOrderedDescending) ?  @"day" : @"night" )
                                                          : @"night";
                                                          
                                                          WASeason season = [NSDate seasonByHemisphere:location.hemisphere];
                                                          NSString *seasonString = [NSDate seasonStringRespesentation:season];
                                                          
                                                          [self willChangeValueForKey:@"locationsWeathers"];
                                                          
                                                          [self.innerLocationsWeathers setObject:curWeather forKey:locationKey];
                                                          
                                                          [self didChangeValueForKey:@"locationsWeathers"];
                                                          dispatch_async(dispatch_get_main_queue(), ^{
                                                              
                                                              [[NSNotificationCenter defaultCenter] postNotificationName:kLocationWeatherDidUpdate object:locationKey];
                                                          });
                                                          [WAFlickrManager getWeatherBackgroundByTags:@[curWeather.weatherDescription, dayCondition, seasonString]
                                                                                          forLocation:location
                                                                                           completion:^(NSImage *image) {
                                                                                               
                                                                                               curWeather.weatherBg = image;
                                                                                               
                                                                                               dispatch_async(dispatch_get_main_queue(), ^{
                                                                                                   
                                                                                                   [[NSNotificationCenter defaultCenter] postNotificationName:kLocationWeatherBackgroundDidUpdate object:locationKey];
                                                                                               });
                                                                                           }];
                                                          
                                                          
                                                          
                                                      }
                                                  }];
}
+(NSSet *)keyPathsForValuesAffectingLocations
{
    return [NSSet setWithObject:@"locationsWeathers"];
}
+(NSSet *)keyPathsForValuesAffectingLocationsWeathers
{
    return [NSSet setWithObject:@"locations"];
}
-(void)updateLocationForKey:(NSObject <NSCopying> *)locationKey
{
    NSString *locKey = [locationKey castToClass:[NSString class]];
    WALocation *location = nil;
    if (locKey && [locKey isEqualToString:kCurrentLocationKey]) {
        
        location = self.currentLocation;
    }
    else {
        
        location = [locationKey castToClass:[WALocation class]];
    }
    
    [self getWeatherForLocation:location forKey:locationKey];
    
}

-(void)locationDidUpdate:(NSNotification *)notification
{
    WALocation *location = notification.object;
    id key = location;
    if ([location isEqualToLocation:self.currentLocation]) {
        
        key = kCurrentLocationKey;
    }
    [self updateLocationForKey:key];
}

-(void)startMonitoringLocation
{
    [self.locationManager startMonitoringSignificantLocationChanges];
}

-(void)getCurrentLocation
{
    CLLocation *curLocation = self.locationManager.location;
    if (curLocation) {
        
        self.currentLocation = [[WALocation alloc] initWithLocation:curLocation];
    }
    else {
        
        [self.locationManager startUpdatingLocation];
    }
}
-(WALocation *)locationForKey:(NSObject *)locationKey
{
    WALocation *location = [locationKey castToClass:[WALocation class]];
    NSString *locationString = [locationKey castToClass:[NSString class]];
    if (locationString) {
        
        if ([locationString isEqualToString:kCurrentLocationKey]) {
            
            location = self.currentLocation;
        }
    }
    return location;
}

-(CLLocationManager *)locationManager
{
    if (!_locationManager) {
        
        _locationManager = [[CLLocationManager alloc] init];
        _locationManager.delegate = self;
    }
    return _locationManager;
}

#pragma mark - CLLocationManagerDelegate
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
    [self.locationManager stopUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    [self.locationManager stopUpdatingLocation];
    self.currentLocation = [[WALocation alloc] initWithLocation:[locations firstObject]];
}
@end
